#include "event_manager.h"

OPEN_JLIB_NS


bool EventManager::add (Node *node, s64 priority) noexcept {
  debug_assert(node);
  auto iter = _map.find(node);
  if (iter != _map.end())
    return false;
  auto entryIter = _map.emplace(node);
  if (!entryIter.second)
    return false;
  auto &entry = entryIter.first->second;
  entry.node = node;
  entry.priority = priority;
  _queue.push_back(&entry.joint);
  _dirty = true;
}

bool EventManager::remove (Node *node) {
  auto iter = _map.find(node);
  if (iter == _map.end())
    return false;
  iter->second.joint.detach();
  _map.erase(iter);
  return true;
}

//void EventManager::foreach (const handler_t &handler) {
//  if (_dirty) {
//    _queue.fast_sort(&comparePriority);
//    _dirty = false;
//  }
//  for (auto iter = _queue.next(); iter != &_queue; iter = iter->next()) {
//    auto entry = iter->cast(&Entry::joint);
//    if (handler(entry->node.ptr()))
//      break;
//  }
//}

void EventManager::clear () {
  _map.clear();
  _queue.clear();
}

inline s64 compareRenderPriority (Node *ln, s64 ld, Node *rn, s64 rd) noexcept {
  if (ld < rd) {
    for (; ld + 1 < rd; --rd)
      rn = rn->parent();
    if (ln == rn->parent())
      return -rn->drawFullOrder();
    rn = rn->parent();
  }
  else if (ld > rd) {
    for (; rd + 1 < ld; --ld)
      ln = ln->parent();
    if (rn == ln->parent())
      return -ln->drawFullOrder();
    ln = ln->parent();
  }
  else if (ln == rn) {
    return 0;
  }
  auto lp = ln->parent();
  auto rp = rn->parent();
  while (lp != rp) {
    if (!lp || !rp)
      return 0;
    ln = lp;
    rn = rp;
    lp = ln->parent();
    rp = rn->parent();
  }
  return ln->drawFullOrder() - rn->drawFullOrder();
}

void EventManager::reorder () noexcept {
  if (!_dirty)
    return;
  _queue.fast_sort([this] (List *lhs, List *rhs) -> s64 {
    auto l = lhs->cast(&Entry::joint);
    auto r = rhs->cast(&Entry::joint);
    auto d = l->priority - r->priority;
    if (d)
      return d;
    if (l->priority != RenderPriority)
      return 0;
    auto ln = l->node.ptr();
    auto ld = computeDepth(ln);
    if (ld < 0)
      return 1;
    auto rn = r->node.ptr();
    auto rd = computeDepth(rn);
    if (rd < 0)
      return -1;
    return compareRenderPriority(ln, ld, rn, rd);
  });
  _dirty = false;
}


CLOSE_JLIB_NS
